home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
cmln0986.arc
/
AIEYE.LTG
< prev
next >
Wrap
Text File
|
1986-08-21
|
9KB
|
203 lines
Listing 1: Unify in Common Lisp
è;;; Unify a pattern list P with an example list E, returning bindings B.
;;; Either P or E may contain pattern variables.
(DEFUN UNIFY (P E &OPTIONAL (B '(NIL)))
(COND ((NULL B) NIL) ;Boundary case--fail if nil bindings
((OR (EQUAL P '_) (EQUAL E '_) ;If P or E is anonymous var '_' or
(EQUAL P E)) B) ; if P = E, succeed w/ B unchanged
((VAR? P) (BIND (NAME P) E B)) ;If P is a var, bind it and succeed
((VAR? E) (BIND (NAME E) P B)) ;If E is a var, bind it and succeed
((OR (ATOM P) (ATOM E)) NIL) ;If P or E is an atom, must fail
((UNIFY (CDR P) (CDR E) ;Else they are lists, unify tails
(UNIFY (CAR P) (CAR E) B))))) ; with bindings from unifying heads
;;; Check if the argument, ITEM, is a variable of the form '(= varname)
(DEFUN VAR? (ITEM)
(AND (CONSP ITEM) (EQ (CAR ITEM) '=)))
;;; Return the name of a variable of the form '(= varname)
(DEFUN NAME (ITEM) (CADR ITEM))
;;; Bind a variable called NAME to a VALUE and return the updated BINDINGS
;;; or NIL if NAME is already bound to a different value. Note that if
;;; NAME is already bound, BIND returns the result of recursively
;;; unifying the variable with the previously stored value.
(DEFUN BIND (NAME VALUE BINDINGS)
(LET ((BINDING (ASSOC NAME BINDINGS))) ;Look up old binding
(COND ((NULL BINDING) ;If there was none,
(CONS (LIST NAME VALUE) BINDINGS)) ; add one now using VALUE
((UNIFY (CADR BINDING) VALUE BINDINGS))))) ;Else unify w/ bound value
Listing 2: AIML -- AI Matching Language
% Conventions for variable names:
% P, E: Pattern and Example, both lists or nested lists.
% PH, PT: Pattern Head, Pattern Tail
% EH, ET: Example Head, Example Tail
% B: Bindings finally resulting from a match.
% M: Match value: head elements of example that were matched.
% R: Remainder: tail elements of example that weren't matched.
% Variables with integer suffixes like B1 and M2 are intermediates Bindings,
% Match values, and so on resulting from nested calls to match.
%
% NOTE: You'll need the bind, append, and member predicates from May's column.
%
% NOTE: If your Prolog doesn't like Match's use of *, ++, ~, etc. for pattern
% operators, try quoting them, redefining them using the op orè% equivalent predicate, or change them to other symbols or alpha names.
[1] % Defined for convenience: match pattern (P) to example (E).
match(P, E) :- match(P, E, _, [], [], _).
[2] % Defined for convenience: match pattern (P) to example (E)
% under bindings (B).
match(P, E, B) :- match(P, E, _, [], [], B).
[3] % Null pattern returns [] as match value and example (E) as
% match remainder.
match([], E, [], E, B, B).
[4] % If pattern and example heads (EH) match, try matching tails (PT, ET)
% and then add EH to the resulting match value (M). The remainder (R)
% from matching tails will be the remainder for the whole operation.
match([EH | PT], [EH | ET], [EH | M], R, B1, B) :-
atomic(EH), % Rule doesn't apply if heads are lists
match(PT, ET, M, R, B1, B). % (in that case, the last rule applies)
[5a] % ? matches one element (EH), so try matching PT to ET.
match([? | PT], [EH | ET], [EH | M], R, B1, B) :-
match(PT, ET, M, R, B1, B). % Match the pattern and example tails
[5b] % ? can also match zero elements, so try matching PT to whole of E.
match([? | PT], E, M, R, B1, B) :-
match(PT, E, M, R, B1, B). % Match PT to whole example
[6] % - operator matches exactly one element, like first rule for ?.
match([- | PT], [EH | ET], [EH | M], R, B1, B) :-
match(PT, ET, M, R, B1 ,B).
[7] % * operator matches zero or more elements.
match([* | PT], E, M, R, B1, B) :-
append(EH, ET, E), % Carve head sublist (EH) from E
match(PT, ET, M1, R, B1, B), % Match what's left--ET
append(EH, M1, M). % Add EH to resulting match value M1
[8] % + operator matches 1 or more, so just replace it with -,*
match([+ | PT], E, M, R, B1, B) :-
match([-, * | PT], E, M, R, B1, B).
[9] % [=, N | PH] binds N to the result of matching PH to E, assuming the
% rest of the pattern (PT) matches the remainder (R) of from this match.
match([[=, N | PH] | PT], E, M, R, B1, B) :-
match(PH, E, M1, R1, B1, B2), % Match head part of pattern
bind([N | M1], B2, B3), % Bind match value M1 to var name N
match(PT, R1, M2, R, B3, B), % Match rest of pattern PT to
append(M1, M2, M). % remainder R from first match
% and append the PH & PT match values
[10] % [~ | PH] succeeds if PH doesn't match any head sublist of E.
match([[~ | PH] | PT], E, M, R, B1, B) :-
not(match(PH, E, _, _, B1, _)), % See if PH matches, then negate
match(PT, E, M, R, B1 ,B). % Match rest of pattern PT to example Eè
[11a] % [?? | PH] succeeds of PH matches a head sublist of E zero or one times.
% First rule: check for matching PH zero times.
match([[?? | PH] | PT], E, M, R, B1, B) :-
match(PT, E, M, R, B1, B). % Discard operator to match zero times
[11b] % Second rule for ??: Check for matching PH once.
match([[?? | PH] | PT], E, M, R, B1, B) :-
match(PH, E, M1, R1, B1, B2), % Match PH once
match(PT, R1, M2, R, B2, B), % Match PT to remainder from 1st match
append(M1, M2, M). % And combine the two match values
[12a] % [++ | PH] succeeds of PH matches a head sublist of E one or more times.
% First rule: check for a single match
match([[++ | PH] | PT], E, M, R, B1, B) :-
match(PH, E, M1, R1, B1, B2), % Match PH once
match(PT, R1, M2, R, B2, B), % Match PT to remainder from 1st match
append(M1, M2, M). % And combine the two match values
[12b] % Second rule for ++: Check for more than one match.
match([[++ | PH] | PT], E, M, R, B1, B) :-
match(PH, E, M1, R1, B1, B2), % Match PH once
match([[++ | PH] | PT], R1, M2, R, B2, B), % Then see if it matches again
append(M1, M2, M).
[13] % [# | PL] matches if any member of the list of patterns PL matches.
match([[# | PL] | PT], E, M, R, B1, B) :-
member(PH, PL), % Get a member from the pattern list
match(PH, E, M1, R1, B1, B2), % Try matching it
match(PT, R1, M2, R, B2, B), % Match remainder R1 to rest of pattern
append(M1, M2, M). % And append the two match values
[14] % [@, PN] matches the pattern named PN to E, then matches the resulting
% remainder (R) to the rest of the pattern (PT).
match([[@, PN] | PT], E, M, R, B1, B) :-
pattern(PN, PH), % Find pattern PH for pattern name PN
append(PH, PT, P), % Add PH to rest of pattern
match(P, E, M, R, B1, B). % And proceed with match
[15] % [:, F | PH] matches the pattern PH to E, then calls the function F with
% the resulting match value (M) as an argument, and finally
match([[: , F | PH] | PT], E, M, R, B1, B) :-
match(PH, E, M1, R1, B1, B2), % Match head part of pattern
Pred =.. [F , M1], % Make match value M1 into args for
call(Pred), % the functor F and call it
match(PT, R1, M, R, B2, B). % Match rest of pattern PT to remainder
% R1 from first match
[16] % [/, N | PH] returns as its match value the named structure N(M),
% where M is the match value from matching PH to the example E.
match([[/, N | PH] | PT], E, [M | M2], R, B1, B) :-
match(PH, E, M1, R1, B1, B2), % Match head part of pattern
match(PT, R1, M2, R, B2, B), % Match tail part of pattern
M =.. [N | M1]. % Make the structured match value
è[17] % [\ | PH] causes PH to return no match value (\ eats the match value).
match([[\ | PH] | PT], E, M, R, B1, B) :-
match(PH, E, _, R1, B1, B2), % Match PH and throw away match value
match(PT, R1, M, R, B2, B). % Final match M value is due to PT only
[18] % If we get here, pattern head isn't a pattern op, match recursivley.
match([PH | PT], [EH | ET], [M1 | M2], R, B1, B) :-
match(PH, EH, M1, [], B1, B2), % See if heads match with no remainder
match(PT, ET, M2, R, B2, B). % If so, match tails
Listing 3: Lisp/Scheme Benchmarks (Scheme version)
;;; T1: CONS performance
(DEFINE T1
(LAMBDA (N)
(IF (< N 2) '(1) (CONS N (T1 (- N 1))) )))
;;; T2: Integer math performance
(DEFINE T2
(LAMBDA (N)
(IF (< N 2) 1 (+ (T2 (- N 1)) (T2 (- N 2))) )))
;;; T3: Iteration performance
(DEFINE T3
(LAMBDA (N)
(DO ((I N (- I 1)))
((= I 0)) )))